import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:x3_base_core/x3_base_core.dart';
import 'package:x3_component_core/x3_component_core.dart';

/// 基本 TextField
class BaseTextField extends StatefulWidget {
  /// 初始值
  final String value;

  /// 提示文本
  final String hintText;

  /// 前缀
  final Widget prefix;

  /// 后缀
  final Widget suffix;

  /// 边框
  final InputBorder inputBorder;

  /// 键盘按钮
  final TextInputAction textInputAction;

  /// 键盘类型
  final TextInputType keyboardType;

  /// 是否只读
  final bool readOnly;

  /// 是否模糊文本
  final bool obscureText;

  /// 是否默认获取焦点
  final bool autoFocus;

  /// 输入框的控制器 可以不传 不传自己构造一个
  final TextEditingController controller;

  /// 把该输入框的焦点暴露出去
  final void Function(FocusNode focusNode) emitFocusNode;

  /// 失去焦点执行事件
  final Function(String text) loseFocusExecutionEvent;

  /// 点击事件
  final GestureTapCallback onTap;

  /// 编辑完成的事件
  final ValueChanged<String> onChanged;

  /// 回车事件
  final ValueChanged<String> onSubmitted;

  /// 完成编辑事件
  final VoidCallback onEditingComplete;

  /// 清空事件
  final VoidCallback onClearOut;

  /// 填充颜色
  final Color fillColor;

  /// 是显示清除小图标
  final bool isShowClearIcon;

  /// 清除图标间距
  final EdgeInsets clearIconMargin;

  /// 后缀组件的宽度
  final double suffixMaxWidth;

  final EdgeInsetsGeometry contentPadding;

  /// 数据限制
  final List<TextInputFormatter> inputFormatters;

  /// 输入内容显示的最大行数
  final int maxLines;

  /// ConstrainedBox的maxHeight
  final double maxHeight;

  /// 焦点控制器
  final FocusNode focusNode;

  /// 需要触发的关键字
  final Set<String> triggerKeyword;

  /// 触发关键字时的回调
  final Function(String keyword) onKeywordTriggeredCallback;

  /// 是否选中已有的文本
  final bool selectedExistValue;

  /// 样式
  final TextStyle style;

  /// 隐藏obscure按钮
  final bool hideObscureButton;

  final TextAlign textAlign;

  BaseTextField({
    Key key,
    this.value,
    this.hintText = '请输入...',
    this.onChanged,
    this.controller,
    this.emitFocusNode,
    this.inputBorder,
    this.prefix,
    this.suffix,
    this.textInputAction,
    this.keyboardType,
    this.onSubmitted,
    this.onClearOut,
    this.onTap,
    this.onEditingComplete,
    this.readOnly = false,
    this.obscureText = false,
    this.autoFocus = false,
    this.fillColor,
    this.isShowClearIcon = true,
    this.clearIconMargin = EdgeInsets.zero,
    this.suffixMaxWidth = 0.0,
    this.contentPadding,
    this.inputFormatters,
    this.maxLines = 1,
    this.maxHeight = 40,
    this.focusNode,
    this.triggerKeyword,
    this.onKeywordTriggeredCallback,
    this.selectedExistValue = false,
    this.style,
    this.hideObscureButton = false,
    this.loseFocusExecutionEvent,
    this.textAlign = TextAlign.start,
  }) : super(key: key) {
    if (onKeywordTriggeredCallback != null) assert(triggerKeyword != null && triggerKeyword.isNotEmpty);
  }

  @override
  _BaseTextFieldState createState() => _BaseTextFieldState();
}

class _BaseTextFieldState extends State<BaseTextField> {
  /// 默认的控制器 因为构造函数不能使用new的对象作为默认值
  TextEditingController _textController;

  /// 焦点控制器
  FocusNode _focusNode;

  TextInputType keyboardType = TextInputType.text;
  bool obscureText = false;

  /// 保存上一次输入的内容
  String _previousValue = "";

  /// 将Set关键字转为列表
  List<String> keywordList;
  RegExp keywordRegex;

  /// 后缀组件的最大宽度约束
  double get suffixMaxWidthConstraints => widget.suffixMaxWidth + (widget.isShowClearIcon ? 32.0 + widget.clearIconMargin.right + widget.clearIconMargin.left : 0.0) + (widget.suffix != null && !widget.readOnly ? 12.0 : 0.0) + (widget.keyboardType == TextInputType.visiblePassword ? 32.0 + 12.0 : 0.0 + 20.0);

  /// 高亮线条
  InputBorder get darkColorBorder {
    if (widget.inputBorder != null) {
      Color color = Theme.of(context).primaryColor;
      Color borderColor = color == Colors.white ? Color(0xFF333333) : color;
      return widget.inputBorder.copyWith(borderSide: widget.inputBorder.borderSide.copyWith(color: borderColor));
    }
    return null;
  }

  @override
  void initState() {
    this._initTextEditController();
    if (widget.keyboardType != null) keyboardType = widget.keyboardType;
    if (widget.obscureText || keyboardType == TextInputType.visiblePassword) obscureText = true;
    _focusNode = widget.focusNode ?? FocusNode();
    _focusNode.addListener(() {
      if (!_focusNode.hasFocus && widget.loseFocusExecutionEvent != null && mounted) widget.loseFocusExecutionEvent(_textController.text);
    });
    if (widget.value != null) {
      _textController.text = widget.value.toString();
      if (widget.selectedExistValue) _textController.selection = TextSelection(baseOffset: 0, extentOffset: _textController.text.length);
    }
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (widget.emitFocusNode != null) widget.emitFocusNode(this._focusNode);
    });
    this._textController.addListener(() {
      setState(() {});
      if (widget.onChanged != null) widget.onChanged(this._textController.text);
      _onSpecialCharInput();
    });
    super.initState();
    if (widget.triggerKeyword != null) keywordList = [...widget.triggerKeyword.toList()];
    if (widget.triggerKeyword != null) keywordRegex = RegExp('\u200B(' + keywordList.map((keyword) => RegExp.escape(keyword)).join('|') + ')\u200B');
  }

  @override
  void didUpdateWidget(covariant BaseTextField oldWidget) {
    if (widget.value != oldWidget.value) _textController.text = widget.value;
    if (widget.obscureText != oldWidget.obscureText) togglePasswordState(isDisplay: !widget.obscureText);
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(constraints: BoxConstraints(maxHeight: widget.maxHeight), child: _buildLoadModulesOnDemand());
  }

  /// 按需填装
  Widget _buildLoadModulesOnDemand() {
    return _buildTextField();
  }

  Widget _buildTextField() {
    return TextField(
      textAlign: widget.textAlign,
      inputFormatters: widget.inputFormatters,
      obscureText: obscureText,
      keyboardType: keyboardType,
      textInputAction: widget.textInputAction ?? TextInputAction.done,
      controller: _textController,
      style: widget.style ?? BaseStyles.bodyMedium(context),
      focusNode: _focusNode,
      cursorColor: BaseStyles.bodyMedium(context).color,
      cursorWidth: 1,
      maxLines: widget.maxLines,
      readOnly: widget.readOnly,
      autofocus: widget.autoFocus,
      decoration: InputDecoration(
        fillColor: widget.fillColor ?? Colors.white,
        hintText: widget.hintText,
        hintStyle: Theme.of(context).inputDecorationTheme.hintStyle,
        contentPadding: widget.contentPadding ?? EdgeInsets.symmetric(vertical: 4),
        border: widget.inputBorder ?? OutlineInputBorder(borderSide: BorderSide.none),
        focusedBorder: darkColorBorder,
        enabledBorder: widget.inputBorder,
        filled: true,
        suffixIcon: _buildSuffixIcon(),
        suffixIconConstraints: BoxConstraints(maxHeight: widget.maxHeight, maxWidth: suffixMaxWidthConstraints),
        prefixIcon: widget.prefix != null ? Row(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [widget.prefix]) : null,
        prefixIconConstraints: widget.prefix != null ? BoxConstraints(minWidth: 28, maxHeight: widget.maxHeight, minHeight: widget.maxHeight) : BoxConstraints(maxWidth: 0),
      ),
      // 点击事件
      onTap: widget.onTap,
      // 提交内容时回调
      onEditingComplete: widget.onEditingComplete,
      // 用户提示完成时回调
      onSubmitted: widget.onSubmitted,
    );
  }

  Widget _buildSuffixIcon() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      mainAxisSize: MainAxisSize.min,
      children: [
        if (widget.isShowClearIcon && _textController.text.isNotEmpty) _buildClean(),
        if (widget.suffix != null && !widget.readOnly) SizedBox(width: 12.0),
        if (widget.suffix != null) widget.suffix,
        if (widget.keyboardType == TextInputType.visiblePassword && !widget.hideObscureButton) SizedBox(width: 12.0),
        if (widget.keyboardType == TextInputType.visiblePassword && !widget.hideObscureButton) BaseDisplayButton(onClick: togglePasswordState),
      ],
    );
  }

  /// 清空文本信息
  Widget _buildClean() {
    if (widget.readOnly) return SizedBox();
    return Container(margin: widget.clearIconMargin, child: BaseClearButton(onPress: _clear));
  }

  /// 切换密码显示方式
  void togglePasswordState({@required bool isDisplay}) {
    if (isDisplay) obscureText = false;
    if (!isDisplay) obscureText = true;
    setState(() {});
  }

  void _clear() {
    _textController.clear();
    if (widget.onClearOut != null) {
      //启用这里
      Future.delayed(Duration(milliseconds: 500), () {
        FocusScope.of(context).requestFocus(FocusNode());
      });
      widget.onClearOut();
    }
  }

  void _initTextEditController() {
    if (widget.controller == null) {
      _textController = TextEditingController();
    } else {
      _textController = widget.controller;
    }
  }

  /// 通过该方法实现输入特殊字符触发回调
  void _onSpecialCharInput() {
    if (widget.triggerKeyword == null || widget.triggerKeyword.isEmpty) return;
    final String currentValue = _textController.text;
    final int oldValueLength = _previousValue.length;
    final int newValueLength = currentValue.length;
    final int diff = newValueLength - oldValueLength;
    _previousValue = currentValue;
    // 已经全部删除了，不需要后续处理
    if (_textController.text.isEmpty) return;
    final TextSelection selection = _textController.selection;
    // 用户按下了删除按钮
    if (diff < 0) {
      // 获取结束删除的位置 -- 标志为三个字符："\u200B \u200B"
      // 光标前的文本
      String beforeCursor = currentValue.substring(0, selection.baseOffset);
      // 光标后的文本
      String afterCursor = currentValue.substring(selection.baseOffset);
      int endIndex = getDeleteEndIndex(selection: selection, beforeCursor: beforeCursor, afterCursor: afterCursor);
      if (endIndex == -1) return;
      // 开始删除的位置 -- 获取最后一个符合关键字的索引
      Iterable<RegExpMatch> matches = keywordRegex.allMatches(beforeCursor);
      if (matches.isEmpty) return;
      RegExpMatch lastMatch = matches.last;
      int startIndex = lastMatch.start;
      // 根据开始和结束索引，删除对应文本
      if (startIndex != -1 && endIndex != -1) {
        String newValue = currentValue.substring(0, startIndex) + currentValue.substring(endIndex);
        _previousValue = newValue;
        _textController.value = TextEditingValue(text: newValue, selection: TextSelection.fromPosition(TextPosition(offset: startIndex)));
      }

      return;
    }
    if (selection.extentOffset > 0) {
      final String lastChar = currentValue.substring(selection.extentOffset - 1, selection.extentOffset);
      bool isTrigger = widget.triggerKeyword.contains(lastChar);
      if (isTrigger && widget.onKeywordTriggeredCallback != null) widget.onKeywordTriggeredCallback(lastChar);
    }
  }

  /// 获取结束删除的位置 标志为三个字符："\u200B \u200B"
  int getDeleteEndIndex({@required TextSelection selection, @required String beforeCursor, @required String afterCursor}) {
    // 删除一个字符后，光标前有“\u200B ”，表示已经删除了一个“\u200B” 直接返回当前index即可
    if (beforeCursor.endsWith("\u200B ")) return selection.baseOffset;
    // 删除一个字符后，光标前有“\u200B”，表示已经删除了一个空格“ ”，但是光标后还有“\u200B”也需要删除。所以索引加1
    if (beforeCursor.endsWith("\u200B") && afterCursor.startsWith('\u200B')) return selection.baseOffset + 1;
    // 删除一个字符后,光标后有“\u200B \u200B”，表示刚好在标志前，需要索引+3
    if (afterCursor.startsWith("\u200B \u200B")) return selection.baseOffset + 3;
    return -1;
  }

  @override
  void dispose() {
    _textController.dispose();
    _focusNode.dispose();
    super.dispose();
  }
}
